package com.yuan.base.service.infrastructure.metric;

import com.google.common.collect.Lists;
import io.micrometer.core.instrument.*;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * prometheus统一埋点工具
 * @author lintiangang
 * @date 2021/03/26 09:27
 **/
@Component
@Slf4j
public class PrometheusMetrics implements InitializingBean {

    @Autowired
    private PrometheusMeterRegistry registry;

    private final ConcurrentMap<String, Gauge> gauges = new ConcurrentHashMap<>();
    private final ConcurrentMap<String, Timer> timers = new ConcurrentHashMap<>();
    private final ConcurrentMap<String, Counter> counters = new ConcurrentHashMap<>();
    private final ConcurrentMap<String, DistributionSummary> summarys = new ConcurrentHashMap<>();

    @Value("${spring.application.name}")
    private String serviceName;

    /**
     * 创建并缓存counter
     */
    public Counter getOrRegisterCounter(String name, String helpDoc, Tag... tags) {
        List<Tag> tagList = Lists.newArrayList(tags);
        return counters.computeIfAbsent(buildCacheKey(name, tagList), k -> {
            Counter counter = Counter.builder(serviceName + "_" + name)
                    .tags(tagList)
                    .description(helpDoc)
                    .register(registry);
            return counter;
        });
    }

    /**
     * 创建并缓存gauge
     */
    public Gauge getOrRegisterGauge(String name, String helpDoc, Tag... tags) {
        List<Tag> tagList = Lists.newArrayList(tags);
        return gauges.computeIfAbsent(buildCacheKey(name, tagList), k -> {
            AtomicInteger atomicInteger = new AtomicInteger();
            Gauge gauge = Gauge.builder(serviceName + "_" + name, atomicInteger, AtomicInteger::get)
                    .tags(Lists.newArrayList(tags))
                    .description(helpDoc)
                    .register(registry);
            return gauge;
        });
    }

    public Timer getOrRegisterTimer(String name, String helpDoc, Tag... tags) {
        List<Tag> tagList = Lists.newArrayList(tags);
        return timers.computeIfAbsent(buildCacheKey(name, tagList), k -> {
            Timer timer = Timer.builder(serviceName + "_" + name)
                    .tags(Lists.newArrayList(tags))
                    .description(helpDoc)
                    .register(registry);
            return timer;
        });
    }

    public DistributionSummary getOrRegisterSummary(String name, String helpDoc, Tag... tags) {
        List<Tag> tagList = Lists.newArrayList(tags);
        return summarys.computeIfAbsent(buildCacheKey(name, tagList), k -> {
            DistributionSummary summary = DistributionSummary.builder(serviceName + "_" + name)
                    .tags(Lists.newArrayList(tags))
                    .description(helpDoc)
                    .register(registry);
            return summary;
        });
    }

    private String buildCacheKey(String name, List<Tag> tagList) {
        return name + "--" + tagList.toString();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.debug(registry.toString());
    }
}
